package cn.iocoder.yudao.module.design.service.taskactionInterface;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.design.annotation.NodeAction;
import cn.iocoder.yudao.module.design.controller.admin.diary.vo.DiaryCreateReqVO;
import cn.iocoder.yudao.module.design.controller.admin.flowtask.vo.FlowTaskBaseVO;
import cn.iocoder.yudao.module.design.dal.dataobject.flow.FlowDO;
import cn.iocoder.yudao.module.design.dal.dataobject.flowtask.FlowTaskDO;
import cn.iocoder.yudao.module.design.dal.dataobject.house.HouseDO;
import cn.iocoder.yudao.module.design.dal.dataobject.houseUserRel.HouseUserRelDO;
import cn.iocoder.yudao.module.design.dal.dataobject.node.NodeDO;
import cn.iocoder.yudao.module.design.dal.mysql.flow.FlowMapper;
import cn.iocoder.yudao.module.design.dal.mysql.flowtask.FlowTaskMapper;
import cn.iocoder.yudao.module.design.dal.mysql.house.HouseMapper;
import cn.iocoder.yudao.module.design.dal.mysql.houseUserRel.HouseUserRelMapper;
import cn.iocoder.yudao.module.design.dal.mysql.node.NodeMapper;
import cn.iocoder.yudao.module.design.service.diary.DiaryService;
import cn.iocoder.yudao.module.design.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.design.enums.design.FlowTaskStatusEnum;
import cn.iocoder.yudao.module.design.enums.design.NodeStatusEnum;
import cn.iocoder.yudao.module.design.enums.user.DesignUserRoleEnum;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * 流程任务处理
 */
@Service
@Validated
@Slf4j
public class FlowTaskActionImpl implements  FlowTaskActionInterface{

    @Resource
    private FlowTaskMapper flowTaskMapper;
    @Resource
    private HouseMapper houseMapper;
    @Resource
    private NodeMapper nodeMapper;


    @Resource
    private FlowMapper flowMapper;

    @Resource
    private HouseUserRelMapper houseUserRelMapper;



    @Resource
    private DiaryService diaryService;



    /**
     * 任务处理-同意-流转
     *
     */
    @Override
    public void confirmAction(Object obj){
        final FlowTaskBaseVO vo = Convert.convert(FlowTaskBaseVO.class, obj);

        // 最终任务项
        NodeDO nextTaskNodeDo = new NodeDO();
        // 查询当前任务明细
        FlowTaskDO flowTaskDO = flowTaskMapper.selectById(vo.getId());
        if(FlowTaskStatusEnum.FLOW_STATUS_ENUM_1.getCode().toString().equals(flowTaskDO.getStatusCd())){
            pushFlowTask(flowTaskDO);
        }else{
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.NODE_DATA_IS_UPDATE);
        }

    }

    /**
     * 任务处理-拒绝-回退
     *
     */
    @Override
    public void refuseAction(Object obj){
        final FlowTaskBaseVO vo = Convert.convert(FlowTaskBaseVO.class, obj);

        if(vo.getNodeId()==null){
            log.info( "由流程进展发起退回：{}",vo   );
            // 此回退由 流程发起
            vo.setNodeId(vo.getId());
        }

        // 最终任务项
        NodeDO nextTaskNodeDo = new NodeDO();
        // 根据nodeId flowCd   statusCd 查询出当前任务所属id
        NodeDO nodeDO = nodeMapper.selectById(vo.getId());
        String isRollback = nodeDO.getIsRollback();
        if(!NodeStatusEnum.NODE_STATUS_ENUM_1.getCode().toString().equals(nodeDO.getStatusCd())){

            throw ServiceExceptionUtil.exception(ErrorCodeConstants.NODE_DATA_IS_UPDATE);
        }
        if("0".equals(isRollback)){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.EXIST_ROLLBACK_TURN_DOWN);
//            throw new NullPointerException("当前节点已回退,不允许多次回退");
        }
        // 判断
        int ptrSortId = Integer.valueOf(nodeDO.getSortId()) - 1;
        QueryWrapper<NodeDO> nodeWrapper = new QueryWrapper<NodeDO>();
        NodeDO preNodeDO = null;
        NodeDO nodeDOPre1 = null;
        NodeDO nodeDOPre2 = null;
        if(0==ptrSortId){
            log.info( "需要流转父节点上一节点最后的子任务：{}",vo   );
            // ptrSortId = 0  表示需要到父节点   查询父节点的上一节点的最后一个任务
            // 查询父任务节点
            nodeDOPre1 = nodeMapper.selectById(nodeDO.getPreId());
            log.info( "父节点：{}",nodeDOPre1  );
            //          上一节点 改为进行中   是否回退 改为是
            if("1".equals(nodeDOPre1.getIsRollback())){
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.EXIST_ROLLBACK_TURN_DOWN,nodeDOPre1.getNodeName());
            }
            int sortIdPre = Integer.valueOf(nodeDOPre1.getSortId()) - 1;
            // 查询父任务节点 上一节点
            nodeWrapper.eq("flow_id", nodeDOPre1.getFlowId());
            nodeWrapper.eq("house_id", nodeDOPre1.getHouseId());
            nodeWrapper.eq("status_cd",NodeStatusEnum.NODE_STATUS_ENUM_2.getCode().toString());
            nodeWrapper.eq("pre_id",nodeDOPre1.getPreId());
            nodeWrapper.eq("sort_id",sortIdPre);

            nodeDOPre2 = nodeMapper.selectOne(nodeWrapper);
            log.info( "父节点上一节点：{}",nodeDOPre2   );
            if("1".equals(nodeDOPre2.getIsRollback())){
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.EXIST_ROLLBACK_TURN_DOWN,nodeDOPre2.getNodeName());
            }
            nodeWrapper = new QueryWrapper<NodeDO>();
            nodeWrapper.eq("pre_id",nodeDOPre2.getId());
            nodeWrapper.eq("status_cd",NodeStatusEnum.NODE_STATUS_ENUM_2.getCode().toString());
            // 算出 节点下有多少子节点  根据sortId 找最后一个任务
            List<NodeDO> nodeDOS = nodeMapper.selectList(nodeWrapper);
            if(CollUtil.isNotEmpty(nodeDOS)){
                for (NodeDO entity: nodeDOS  ) {
                    if(String.valueOf(nodeDOS.size()).equals(entity.getSortId())){
                        preNodeDO = entity;
                        break;
                    }
                }
            }
            nodeDOPre1.setIsRollback("1");
            nodeDOPre1.setStatusCd(NodeStatusEnum.NODE_STATUS_ENUM_1.getCode().toString());
            nodeMapper.updateById(nodeDOPre1);

            nodeDOPre2.setIsRollback("1");
            nodeDOPre2.setStatusCd(NodeStatusEnum.NODE_STATUS_ENUM_1.getCode().toString());
            nodeMapper.updateById(nodeDOPre2);

        }else{

            // 查询上一任务节点
            nodeWrapper.eq("flow_id", nodeDO.getFlowId());
            nodeWrapper.eq("house_id", nodeDO.getHouseId());
            nodeWrapper.eq("status_cd",NodeStatusEnum.NODE_STATUS_ENUM_2.getCode().toString());
            nodeWrapper.eq("pre_id",nodeDO.getPreId());
            nodeWrapper.eq("sort_id",ptrSortId);
            preNodeDO = nodeMapper.selectOne(nodeWrapper);
        }

//          上一节点 改为进行中   是否回退 改为是
        if("1".equals(preNodeDO.getIsRollback())){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.EXIST_ROLLBACK_TURN_DOWN,preNodeDO.getNodeName());
        }
        preNodeDO.setIsRollback("1");
        preNodeDO.setStatusCd(NodeStatusEnum.NODE_STATUS_ENUM_1.getCode().toString());
        nodeMapper.updateById(preNodeDO);

//            上一节点任务由结束改为进行中  结束时间改为空
        FlowDO preFlowDO = flowMapper.selectById(preNodeDO.getFlowId());
        QueryWrapper<FlowTaskDO> preQueryWrapper = new QueryWrapper<FlowTaskDO>();
        preQueryWrapper.eq("status_cd",NodeStatusEnum.NODE_STATUS_ENUM_2.getCode().toString());
        preQueryWrapper.eq("node_id",preNodeDO.getId());
        FlowTaskDO preFlowTaskDO = flowTaskMapper.selectOne(preQueryWrapper);
        preFlowTaskDO.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_1.getCode());
        preFlowTaskDO.setFinishTime(null);
        flowTaskMapper.updateById(preFlowTaskDO);


//          当前节点 改为待开始
        nodeDO.setIsRollback("1");
        nodeDO.setStatusCd(NodeStatusEnum.NODE_STATUS_ENUM_0.getCode().toString());
        nodeMapper.updateById(nodeDO);
//            删除当前任务
        QueryWrapper<FlowTaskDO> queryWrapper = new QueryWrapper<FlowTaskDO>();

        queryWrapper.eq("status_cd",NodeStatusEnum.NODE_STATUS_ENUM_1.getCode().toString());
        queryWrapper.eq("node_id",nodeDO.getId());
        flowTaskMapper.delete(queryWrapper);


    }

    /**
     * 任务处理-查看
     *
     */
    @Override
    public Object viewAction(Object obj){
        final FlowTaskBaseVO vo = Convert.convert(FlowTaskBaseVO.class, obj);

        return null;
    }

    /**
     * 任务补充
     *
     */
    @Override
    public void replenishTask(Object obj){
        final FlowTaskBaseVO vo = Convert.convert(FlowTaskBaseVO.class, obj);
        if(vo.getNodeId()==null){
            // 最终任务项
            NodeDO nextTaskNodeDo = new NodeDO();
            // 根据nodeId flowCd   statusCd 查询出当前任务所属id
            NodeDO nodeDO = nodeMapper.selectById(vo.getId());
            FlowDO flowDO = flowMapper.selectById(vo.getFlowId());
            QueryWrapper<FlowTaskDO> queryWrapper = new QueryWrapper<FlowTaskDO>();

            // 查询当前任务明细
            queryWrapper.eq("flow_cd",flowDO.getFlowCd());
            queryWrapper.eq("status_cd","1");
            queryWrapper.eq("node_id",vo.getId());
            FlowTaskDO flowTaskDO = flowTaskMapper.selectOne(queryWrapper);
            vo.setNodeId(nodeDO.getId());
            vo.setId(flowTaskDO.getId());
        }
        replenishTaskChild(vo);
    }



    /**
     * 提交当前任务，推送新任务
     * @param flowTaskDO 任务详情
     */
    @NodeAction
    public void pushFlowTask( FlowTaskDO flowTaskDO ){
        // 更新流程任务  修改当前节点状态为已完成
        getNextTaskNodeDo(flowTaskDO.getFlowCd(),flowTaskDO.getNodeId());

        // 修改当前任务状态为已完成
        flowTaskDO.setFinishTime(new Date());
        flowTaskDO.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_2.getCode());
        flowTaskMapper.updateById(flowTaskDO);
    }

    public void  replenishTaskChild(FlowTaskBaseVO vo){
        // 保存 日志内容 附件
        final Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        DiaryCreateReqVO diaryCreateReqVO = new DiaryCreateReqVO();
        diaryCreateReqVO.setDate( new Date());
        diaryCreateReqVO.setHouseId(vo.getHouseId());
        diaryCreateReqVO.setFlowId(vo.getFlowId());
        diaryCreateReqVO.setNodeId(vo.getNodeId());
        diaryCreateReqVO.setComment(vo.getRemark());
        diaryCreateReqVO.setCreator(loginUserId.toString());
        diaryCreateReqVO.setFileList(vo.getFileList());
        diaryService.createDiary(diaryCreateReqVO);

    }



    public void saveFlowTask(Long houseId,Long flowId,NodeDO nodeDO) throws ServiceException {
        // 查询 设计流程信息
        QueryWrapper  query = new QueryWrapper();
        query.eq("id",flowId);
        FlowDO flowDO = flowMapper.selectOne(query);
        // 建立项目简介
        QueryWrapper  queryNode = new QueryWrapper();
        queryNode.eq("id",houseId);
        HouseDO houseDO = houseMapper.selectOne(queryNode);
//        String taskType = ""


        // 创建开工信息补充提醒
        FlowTaskDO flowTaskDO = new FlowTaskDO();
        flowTaskDO.setTaskName("任务处理");
        flowTaskDO.setHouseId(houseDO.getId());
        flowTaskDO.setProjectName(houseDO.getProjectName());
        flowTaskDO.setFlowId(flowDO.getId());
        flowTaskDO.setFlowName(flowDO.getFlowName());
        flowTaskDO.setNodeId(nodeDO.getId());
        flowTaskDO.setNodeName(nodeDO.getNodeName());

        Long dealerId = SecurityFrameworkUtils.getLoginUserId();
        String taskType = "1";

        // add by czw 2023年7月14日  增加 预处理角色判断  配置预处理角色 则选择对应角色的用户 start
        String roleId = "";
        if("0".equals(flowDO.getFlowCd())){
            // 设计流程   默认设计师
            roleId = StrUtil.isNotEmpty(nodeDO.getPreRoleId()) ?
                    nodeDO.getPreRoleId(): DesignUserRoleEnum.DESIGN.getRoleId().toString();
        }else if("1".equals(flowDO.getFlowCd())){
            // 采购流程   默认供应商
            roleId = StrUtil.isNotEmpty(nodeDO.getPreRoleId()) ?
                    nodeDO.getPreRoleId(): DesignUserRoleEnum.SUPPLIER.getRoleId().toString();
        }else if("2".equals(flowDO.getFlowCd())){
                // 施工流程   默认项目经理
            roleId = StrUtil.isNotEmpty(nodeDO.getPreRoleId()) ?
                    nodeDO.getPreRoleId(): DesignUserRoleEnum.PROJECT_MANAGER.getRoleId().toString() ;

        }

        String roleName  = DesignUserRoleEnum.getRoleNameByRoleId(Long.valueOf(roleId));
        if(StrUtil.isNotEmpty(roleId)){
            QueryWrapper  queryRel = new QueryWrapper();
            queryRel.eq("house_id",houseId);
            queryRel.eq("status","0");
            queryRel.eq("role_id",roleId);
            HouseUserRelDO houseUserRelDO =  houseUserRelMapper.selectOne(queryRel);
            if(houseUserRelDO==null){
				// 判断是否为空  为空报错
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.RELATION_ROLE_DATA_NOT_EXIST,roleName);
            }
            dealerId = houseUserRelDO.getUserId();
        }
        // add by czw 2023年7月14日  增加 预处理角色判断  配置预处理角色 则选择对应角色的用户 end

        flowTaskDO.setDealerId(dealerId);
        // 0-补充信息 1-任务流转
        flowTaskDO.setTaskType(taskType);
        //,0-待开始1-进行中，2-已完成',
        flowTaskDO.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_1.getCode());
        flowTaskDO.setStartTime(new Date());
        flowTaskDO.setDeleted(false);
        flowTaskDO.setFlowCd(flowDO.getFlowCd());
        flowTaskMapper.insert(flowTaskDO);
    }

    public void getNextTaskNodeDo(Integer flowCd,Long nodeId){

        // 查询任务节点详情
        NodeDO nodeDO = nodeMapper.selectById(nodeId);

        // 查询当前流程同级所有任务节点
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("pre_id", nodeDO.getPreId());
        queryWrapper.eq("flow_id", nodeDO.getFlowId());
        List<NodeDO> nodeList = nodeMapper.selectList(queryWrapper);

        // 判断同级节点任务是否都完成
        //如果 sortId == preNodeList.length  表示 pre_id 对应的node_id 下的所有节点  全部完成
        if(String.valueOf(nodeList.size()).equals(nodeDO.getSortId())){
            if("1".equals(flowCd)){
                // 表示已完成采购流程
                nodeDO.setFinishTime(new Date());
                nodeDO.setStatusCd("2");
                nodeMapper.updateById(nodeDO) ;

                // 上级节点 修改为已完成
                NodeDO preNodeDo = new NodeDO();
                preNodeDo.setId(nodeDO.getPreId());
                preNodeDo.setStatusCd("2");
                preNodeDo.setFinishTime(new Date());
                nodeMapper.updateById(preNodeDo);
                return;
            }
            if(nodeDO.getPreId()!=0){
                // 都完成了  向上找父节点的同级节点
                getNextTaskNodeDo(flowCd,nodeDO.getPreId());

            }else{

                /*当前节点所在流程详情*/
                FlowDO flowDO = flowMapper.selectById(nodeDO.getFlowId());
                // 当前项目所有主流程 0-设计流程  1-采购流程  2-施工流程
                QueryWrapper query = new QueryWrapper();
                query.eq("house_id", flowDO.getHouseId());
                query.ne("flow_cd", flowDO.getFlowCd());
                List<FlowDO> flowDOList = flowMapper.selectList(query);
                if("0".equals(flowDO.getFlowCd())){

                    // 设计流程结束 同时开启 采购流程和施工流程第一项
                    for(FlowDO flow :flowDOList){

                        getNodeFirstItemFirst(flow);
                    }
                }

            }

        }else{

            // 因为  设计流程 完成后 需要同时处理 采购流程和施工流程的首个任务节点 所以不能统一返回NodeDO 做统一处理
            // 这里直接单独处理将任务做成
            NodeDO nextTaskNodeDo = new NodeDO();
            for (NodeDO nodeDoItem:nodeList  ) {
                if(nodeDoItem.getSortId().equals(String.valueOf(Integer.valueOf(nodeDO.getSortId())+1))){

                    nextTaskNodeDo = getNodeFirstItem(nodeDoItem.getId());
                    if(nextTaskNodeDo==null){
                        nextTaskNodeDo = nodeDoItem;
                    }else{

                        // 将任务父节点置为 进行中
                        nodeDoItem.setStartTime(new Date());
                        nodeDoItem.setStatusCd("1");
                        nodeMapper.updateById(nodeDoItem);
                    }

                    // 生成子节点的待办任务 同时将子节点  改为进行中
                    saveFlowTask(nextTaskNodeDo.getHouseId(),nextTaskNodeDo.getFlowId(),nextTaskNodeDo);
                    nextTaskNodeDo.setStartTime(new Date());
                    nextTaskNodeDo.setStatusCd("1");
                    nodeMapper.updateById(nextTaskNodeDo);
                    break;
                }
            }

//            saveFlowTask(nextTaskNodeDo.getHouseId(),nextTaskNodeDo.getFlowId(),nextTaskNodeDo);

        }
        /*上级节点 修改为已完成*/
        nodeDO.setFinishTime(new Date());
        nodeDO.setStatusCd("2");
        nodeMapper.updateById(nodeDO) ;

    }

    public void getNodeFirstItemFirst(FlowDO flow){
        // 采购流程直接开启所有采购任务
        if("1".equals(flow.getFlowCd())){

            QueryWrapper preNodeListQuery = new QueryWrapper();
            preNodeListQuery.eq("flow_id",flow.getId());
            preNodeListQuery.eq("pre_id",0);
            List<NodeDO> preNodeList = nodeMapper.selectList(preNodeListQuery);
            for (NodeDO nodeDo:preNodeList  ) {
                // 将首节点置为进行中
                nodeDo.setStartTime(new Date());
                nodeDo.setStatusCd("1");
                nodeMapper.updateById(nodeDo) ;
                // 查询当前流程子节点的第一个节点 直到最后一个节点
                // 并将每个子节点的首节点  改为进行中
                NodeDO nodeFirstItem = getNodeFirstItem(nodeDo.getId());
                saveFlowTask(flow.getHouseId(),flow.getId(),nodeFirstItem);
            }
        }else{
            // 查询所属流程中 第一个节点
            QueryWrapper preNodeQuery = new QueryWrapper();
            preNodeQuery.eq("flow_id",flow.getId());
            preNodeQuery.eq("pre_id",0);
            preNodeQuery.eq("sort_id",1);

            NodeDO nodeFirst = nodeMapper.selectOne(preNodeQuery);
            if(nodeFirst==null){
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.SG_FLOW_NOT_CREATE_TO);
            }
            // 将首节点置为进行中
            nodeFirst.setStartTime(new Date());
            nodeFirst.setStatusCd("1");
            nodeMapper.updateById(nodeFirst) ;
            // 查询当前流程子节点的第一个节点 直到最后一个节点
            // 并将每个子节点的首节点  改为进行中
            NodeDO nodeFirstItem = getNodeFirstItem(nodeFirst.getId());
            saveFlowTask(flow.getHouseId(),flow.getId(),nodeFirstItem);
        }


        // 采购发送给设计师 补充待办

        // 施工发送给项目经理补充待办

//        if("1".equals(flowDO.getFlowCd())){
//            //表示所有采购项目完成  后续可作为开关开启指定施工节点
//
//        }
//        if("2".equals(flowDO.getFlowCd())){
//            //表示施工流程所有项目完成 无需流转
//            // 发一笔系统提醒 关闭项目
//        }
    }

    public NodeDO getNodeFirstItem(Long flowId){


        QueryWrapper preNodeQuery = new QueryWrapper();
        preNodeQuery.eq("pre_id",flowId);
        preNodeQuery.eq("sort_id",1);
        NodeDO nodeFirst = nodeMapper.selectOne(preNodeQuery);

        if(nodeFirst!=null){
            nodeFirst.setStartTime(new Date());
            nodeFirst.setStatusCd("1");
            nodeMapper.updateById(nodeFirst);
            NodeDO nodeFirstItem = getNodeFirstItem(nodeFirst.getId());
            nodeFirst.setStartTime(new Date());
            if(nodeFirstItem==null){
                // 修改每个node 状态为进行中
                nodeFirst.setStartTime(new Date());
                nodeFirst.setStatusCd("1");
                nodeMapper.updateById(nodeFirst);
                return nodeFirst;
            }else{
                NodeDO nodeFirstItem1 =   getNodeFirstItem(nodeFirstItem.getId());
                if(nodeFirstItem1==null){
                    // 修改每个node 状态为进行中
                    nodeFirstItem.setStartTime(new Date());
                    nodeFirstItem.setStatusCd("1");
                    nodeMapper.updateById(nodeFirstItem);
                    return nodeFirstItem;
                }
            }
        }

        return null;


    }
}
